#include "tcp_client.h"

namespace rr {
namespace nio {

TcpClient::TcpClient(EventLoop::Var loop)
: loop_(loop)
{
    printf("TcpClient::TcpClient %p\n", this);
}

TcpClient::~TcpClient()
{
    printf("TcpClient::~TcpClient %p\n", this);
}


int32_t TcpClient::Start(InetAddress& peer_addr)
{
    printf("TcpClient::Start peer address[%s:%u]\n", peer_addr.GetIp().c_str(), peer_addr.GetPort());
    uv_con_.data = this;
    uv_tcp_handle_ = std::make_shared<uv_tcp_t>();
    int32_t ret = uv_tcp_init(loop_->GetLoop(), uv_tcp_handle_.get());
    if(ret != 0) {
        printf("TcpClient::Start uv_tcp_init failed, ret:%d\n", ret);
        return -1;
    }

    uv_tcp_handle_->data = this;
    ret = uv_tcp_connect(&uv_con_, uv_tcp_handle_.get(), peer_addr.GetSockAddr(), TcpClient::OnConnect);
    if(ret != 0) {
        printf("TcpClient::Start uv_tcp_connect failed, ret:%d\n", ret);
        return -1;
    }
    EventRecord::Sptr record = std::make_shared<EventRecord>(EventRecord::TCP, uv_tcp_handle_.get());
    loop_->GetEventRecorder()->AddRecord(record);

    printf("TcpClient::End\n");
    return 0;
}

void TcpClient::Close(const CloseCompleteCallback &cb)
{
    printf("TcpClient::Close %p\n", this);
    close_complete_cb_ = cb;

    if(conn_ != nullptr) {
        conn_->Close();
    } else {
        uv_handle_t *handle = (uv_handle_t *)uv_tcp_handle_.get();
        if(handle && !uv_is_closing(handle)) {
            uv_close(handle, TcpClient::OnCloseComplete);
        } else {
            DoCloseComplete();
        }
    }

    return;
}

void TcpClient::OnConnect(uv_connect_t* req, int status)
{
	printf("OnConnect status:%d\n", status);
    TcpClient *client = (TcpClient *)req->data;
    client->DoConnect(status);
    
    return;
}

void TcpClient::OnCloseComplete(uv_handle_t* handle)
{
    printf("OnCloseComplete handle:%p data:%p\n", handle, handle->data);
    TcpClient *client = (TcpClient *)handle->data;
    client->loop_->GetEventRecorder()->RemoveRecord(handle);
    client->DoCloseComplete();
}

void TcpClient::DoConnect(int32_t status)
{
    TcpConnectionVar conn = nullptr;

    if(status < 0) { //faild
		printf("OnConnect Failed, status:%d, reason:%s\n", status, uv_strerror(status));
        if(uv_tcp_handle_ && !uv_is_closing((uv_handle_t *)uv_tcp_handle_.get())) {
            printf("DoConnect uv_close uv_tcp_handle_\n");
            uv_close((uv_handle_t *)uv_tcp_handle_.get(), TcpClient::OnCloseComplete);
        }
    } else {
        printf("OnConnect Success\n");
        conn = std::make_shared<TcpConnection>(loop_, uv_tcp_handle_);
        uv_tcp_handle_ = nullptr;
        conn->SetConCloseCallback(std::bind(&TcpClient::OnConClose, this, std::placeholders::_1));
        conn->SetCloseCompleteCallback(std::bind(&TcpClient::DoCloseComplete, this));
        conn->SetMessageCallback(message_cb_);
        conn_ = conn;
        conn->StartRead();
    }

    if(connection_cb_) {
        connection_cb_(conn);
    }

    return;
}

void TcpClient::OnConClose(TcpConnectionVar conn)
{
    if(con_close_cb_) {
        con_close_cb_(conn);
    }
}

void TcpClient::DoCloseComplete()
{
    if(close_complete_cb_) {
        close_complete_cb_();
    }
}

} //namespace 
} //namespace 
